package empty

import chipsalliance.rocketchip.config.{Config, Parameters}
import chisel3._
import chisel3.util._
import chisel3.internal.sourceinfo.SourceInfo
import chisel3.stage.ChiselStage
import chisel3.util.random.FibonacciLFSR
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.amba.axi4._
import freechips.rocketchip.tilelink.{TLFilter, TLFuzzer, TLRAMModel, TLToAXI4}

object myAxiUtil{
//首先是为不同的模块定义不同的参数，diplomacy提供了标准的定义，以供使用
//1. AXI4MasterPortParameters：依赖于AXI4SlaveParameters
//2. AXI4SlavePortParameters：依赖于AXI4MasterParameters
//这一步对应于Add.scala中的三个case class
//这里我们直接继承这些case class并且进行自定义：
// case class myAXI4MasterParameters(name:String="Axi4Master", id:IdRange=IdRange(0,1)) extends AXI4MasterParameters(name, id)
// case class myAXI4MasterPortParameters(masters:Seq[AXI4MasterParameters]=Seq(myAXI4MasterParameters())) extends AXI4MasterPortParameters(masters)
val myAXI4MasterParameters =  AXI4MasterParameters(name="Axi4Master", id=IdRange(0,2))
val myAXI4MasterPortParameters = Seq(AXI4MasterPortParameters(masters=Seq(myAXI4MasterParameters)))

//两个slave，因此定义两个 AXI4SlavePortParameters
// case class myAXI4SlaveParameters1(
//     address: Seq[AddressSet] = Seq(AddressSet(0x80000000L, 0xffff)),
//     supportsWrite : TransferSizes = TransferSizes(64),
//     supportsRead  : TransferSizes = TransferSizes(64)
//     ) extends AXI4SlaveParameters(address=address, supportsWrite=supportsWrite,supportsRead=supportsRead)
// case class myAXI4SlavePortParameters1(slaves:Seq[AXI4SlaveParameters]=Seq(myAXI4SlaveParameters1()), beatBytes:Int=64
//     ) extends AXI4SlavePortParameters(slaves=slaves, beatBytes=beatBytes)
val myAXI4SlaveParameters1 = AXI4SlaveParameters(
    address = Seq(AddressSet(0x80000000L, 0xffff)),
    supportsWrite= TransferSizes(64),
    supportsRead = TransferSizes(64)
    )
val myAXI4SlavePortParameters1 = Seq(AXI4SlavePortParameters(slaves=Seq(myAXI4SlaveParameters1), beatBytes=64))


// case class myAXI4SlaveParameters2(
//     address: Seq[AddressSet] = Seq(AddressSet(0x90000000L, 0xffff)),
//     supportsWrite : TransferSizes = TransferSizes(64),
//     supportsRead  : TransferSizes = TransferSizes(64)
//     ) extends AXI4SlaveParameters(address=address, supportsWrite=supportsWrite,supportsRead=supportsRead)
// case class myAXI4SlavePortParameters2(slaves:Seq[AXI4SlaveParameters]=Seq(myAXI4SlaveParameters2()), beatBytes:Int=64
//     ) extends AXI4SlavePortParameters(slaves=slaves, beatBytes=beatBytes)
val myAXI4SlaveParameters2 = AXI4SlaveParameters(
    address = Seq(AddressSet(0x90000000L, 0xffff)),
    supportsWrite = TransferSizes(64),
    supportsRead  = TransferSizes(64)
    )
val myAXI4SlavePortParameters2 = Seq(AXI4SlavePortParameters(slaves=Seq(myAXI4SlaveParameters2), beatBytes=64))

// case class myAXI4SlaveParameters3(
//     address: Seq[AddressSet] = Seq(AddressSet(0x00000000L, 0xffffffff)),
//     supportsWrite : TransferSizes = TransferSizes(64),
//     supportsRead  : TransferSizes = TransferSizes(64)
//     ) extends AXI4SlaveParameters(address=address, supportsWrite=supportsWrite,supportsRead=supportsRead)
// case class myAXI4SlavePortParameters3(slaves:Seq[AXI4SlaveParameters]=Seq(myAXI4SlaveParameters3()), beatBytes:Int=64
//     ) extends AXI4SlavePortParameters(slaves=slaves, beatBytes=beatBytes)
val myAXI4SlaveParameters3 = AXI4SlaveParameters(
    address = Seq(AddressSet(0x00000000L, 0xffffffffL)),
    supportsWrite = TransferSizes(64),
    supportsRead  = TransferSizes(64)
    )
val myAXI4SlavePortParameters3 = Seq(AXI4SlavePortParameters(slaves=Seq(myAXI4SlaveParameters3), beatBytes=64))
}
//然后是为定义不同类型的node，以便于和后续模块绑定，主要是两个driver模块、xbar模块和一个accept模块
//1. case class AXI4MasterNode(portParams: Seq[AXI4MasterPortParameters])：用于driver模块
//2. case class AXI4SlaveNode(portParams: Seq[AXI4SlavePortParameters])：用于accept模块
//3. case class AXI4NexusNode(
//  masterFn:       Seq[AXI4MasterPortParameters] => AXI4MasterPortParameters,
//  slaveFn:        Seq[AXI4SlavePortParameters]  => AXI4SlavePortParameters)(
//  implicit valName: ValName):用于xbar模块

//编写AXI4Xbar模块，这一步省略，因为rocket chip库中有，并且已经实现了与AXI4NexusNode节点的绑定，对应于Add.scala中的Adder类；

//编写driver模块
class axi4Driver()(implicit valName:ValName, p:Parameters) extends LazyModule {
    import myAxiUtil._
    val node = AXI4MasterNode(myAXI4MasterPortParameters)
    
    lazy val module = new LazyModuleImp (this) {
        //get the bundles and edge, because it is a source node, it has only the outward bundles and edges
		val (io_out, edge) = node.out(0)
		io_out <> DontCare
		dontTouch(io_out)

		

		// //we neet to use wire to wrap the bundle
		// val wide_bundle = edgesOut.bundle
		// val out = Wire(AXI4Bundle(wide_bundle))
		// io_out :<> out
        // //get the Bits width
        // val addrBits = edgesOut.bundle.addrBits
        // val dataBits = edgesOut.bundle.dataBits
        // val idBits   = edgesOut.bundle.idBits
        // val burstBits = edgesOut.bundle.burstBits
        // val sizeBits = edgesOut.bundle.sizeBits
        // val lenBits    = edgesOut.bundle.lenBits
        // val strbBits  = edgesOut.bundle

        // //aw channel reg
        // val awValidReg = RegInit(false.B)
        // val awIdReg    = RegInit(0.U(idBits.W))
        // val awAddrReg  = RegInit(0.U(addrBits.W))
        // val awLenReg   = RegInit(0.U(lenBits.W))
        // val awSizeReg  = RegInit(0.U(sizeBits.W))
        // val awBurstReg = RegInit(0.U(burstBits.W))
        // //w channel reg
        // val wValidReg = RegInit(false.B)
        // val wIdReg    = RegInit(0.U(idBits.W))
        // val wDataReg  = RegInit(0.U(dataBits.W))
        // val wStrbReg  = RegInit(((1<<(dataBits/8))-1).U((dataBits/8).W))
        // val wLastReg  = RegInit(false.B)
        // //b channel reg
        // val bReadyReg = RegInit(true.B)
        // //ar channel reg
        // val arValidReg = RegInit(false.B)
        // val arIdReg = RegInit(0.U(idBits.W))
        // val arAddrReg = RegInit(0.U(addrBits.W))
        // val arLenReg = RegInit(0.U(lenBits.W))
        // val arSizeReg = RegInit(0.U(sizeBits.W))
        // val arBurstReg = RegInit(0.U(burstBits.W))
        // //r channel reg
        // val rReadyReg = RegInit(true.B)
        // //the state
        // val idle :: addrWrite :: dataWrite :: finish :: Nil = Enum(4)
        // val stateReg = RegInit(idle)
        // val awFire = WireInit(false.B)
        // awFire := awValidReg & io_out.aw.ready
        // val wFire = WireInit(false.B)
        // wFire := wValidReg & io_out.w.ready

        // switch(stateReg){
        //     is(idle){
        //         stateReg := addrWrite//aw channel
        //     }

        //     is(addrWrite){
        //         when(awFire){
        //             stateReg := dataWrite
        //         }
        //     }

        //     is(dataWrite){
        //         when(wFire){
        //             stateReg := finish
        //         }
        //     }

        //     is(finish){
        //         stateReg := finish
        //     }
        // }

        // //aw channel output
        // when(stateReg===addrWrite && !awFire){
        //     awValidReg := true.B
        //     awAddrReg := 1234.U
        // }.otherwise{
        //     awValidReg := false.B
        //     awAddrReg := 0.U
        // }
        // //w channle output
        // when(stateReg===dataWrite && !wFire){
        //     wValidReg := true.B
        //     wDataReg := 12345.U
        // } .otherwise{
        //     wValidReg := false.B
        //     wDataReg := 0.U
        // }
        // //b channel output
        // when(io_out.b.valid){
        //     bReadyReg := false.B
        // }

		// //connect the register to output
		// //aw channel
		// out.aw.valid := awValidReg
		// out.aw.bits.id := awIdReg
		// out.aw.bits.addr := awAddrReg
		// out.aw.bits.len := awLenReg
		// out.aw.bits.size := awSizeReg
		// out.aw.bits.burst := awBurstReg
		// out.aw.bits.lock := DontCare
		// out.aw.bits.qos := DontCare
		// out.aw.bits.cache :=DontCare
		// out.aw.bits.prot := DontCare
		
		// //w channel
		// out.w.valid := wValidReg
		// out.w.bits.data := wDataReg
		// out.w.bits.last := wLastReg
		// out.w.bits.strb := wStrbReg
		// //io_out.w.bits.id := wIdReg//id removed in axi4
		
		// //b channel
		// out.b.ready := bReadyReg
		
		// //ar channel
		// out.ar.valid := arValidReg
		// out.ar.bits.id := arIdReg
		// out.ar.bits.addr := arAddrReg
		// out.ar.bits.len := arLenReg
		// out.ar.bits.size := arSizeReg
		// out.ar.bits.burst := arBurstReg
		// out.ar.bits.prot := DontCare
		// out.ar.bits.qos := DontCare
		// out.ar.bits.lock := DontCare
		// out.ar.bits.cache := DontCare
		
		// //r channel
		// out.r.ready := rReadyReg

	}
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    //    val (out, edge) = node.out(0)//out return a seq of (bundleOut, edgeOut), use "(0)" to select the first one

    //    val maxTransfer = edge.slave.maxTransfer
    //    val beatBytes   = edge.slave.beatBytes
    //    val addressBits = edge.slave.maxAddress
    //    val sizeBits    = edge.bundle.sizeBits
    //    val dataBits    = edge.bundle.dataBits
    //    val idBits      = edge.bundle.idBits
    //    val burstBits   = edge.bundle.burstBits

    //    val idle :: addrWrite :: dataWrite :: finish :: Nil = Enum(4)
    //    val stateReg = RegInit(idle)

    //    val awBitsReg = RegInit(0.U(32.W))
    //    val awValidReg = RegInit(false.B)
    //    val awBurstReg = RegInit(0.U(burstBits.W))
    //    val awidReg   = RegInit(0.U(idBits.W))

    //    val wBitsReg = RegInit(0.U(512.W))
    //    val wValidReg = RegInit(false.B)
    //    val widReg   = RegInit(0.U(idBits.W))
    //    val wStrbReg = RegInit(0xffffffffL.U(64.W))

    //    switch(stateReg){
    //        is(idle){
    //            awBitsReg := 0.U(32.W)
    //            awValidReg := true.B
    //            stateReg := addrWrite
    //        }

    //        is(addrWrite){
    //            when(out.aw.ready){
    //                awValidReg := false.B
    //                stateReg := dataWrite
    //            }
    //        }

    //        is(dataWrite){
    //            wBitsReg := 0xefef.U(512.W)
    //            wValidReg := true.B
    //            stateReg := finish
    //        }
    //        is(finish){
    //            when(out.w.ready){
    //                wValidReg := false.B
    //                stateReg := stateReg
    //            }
    //        }
    //    }

    //    out.aw.valid := awValidReg
    //    out.aw.bits.addr  := awBitsReg
    //    out.aw.bits.id := awidReg
    //    out.aw.bits.burst := awBurstReg

    //    out.w.valid := wValidReg
    //    out.w.bits.data := wBitsReg
    //    out.w.bits.strb := wStrbReg
    // }
    override lazy val desiredName = "axi4Driver"
}

//编写accept模块
class axi4Accept()(implicit valName:ValName, p:Parameters) extends  LazyModule {
    import myAxiUtil._
    val node = AXI4SlaveNode(myAXI4SlavePortParameters3)//使用myAXI4SlavePortParameters3，接受32bit的所有参数；

    lazy val module = new LazyModuleImp (this) {
		val (io_in, edge) = node.in(0)
		dontTouch(io_in)
    }
    override lazy val desiredName = "axi4Accept"
}

//编写顶层
class xbarTestHarness()(implicit valName:ValName, p:Parameters) extends LazyModule {
    import myAxiUtil._
    val numSlaves = 2
    //two axi4 drivers
    val drivers = Seq.fill(numSlaves){
        LazyModule(new axi4Driver())
    }

    //TLFuzzer drives test traffic over TL2 links;It generates a sequence of randomized
    //requests, and issues legal ones into the DUT.
    //val drivers = Seq.fill(numSlaves) { LazyModule(new TLFuzzer(4, 4, nOrdered = Some(1))) }
    //val drivers = Seq.fill(numSlaves) { LazyModule(new AXI4FuzzMaster(txns=4)) }

    //one axi4 accepter
    //val accept = LazyModule(new axi4Accept())
    
	val accept = LazyModule(new AXI4RAM(address=AddressSet(0x00000000L, 0xfffffL), beatBytes=64))
	//val accept = AXI4RAM(address=AddressSet(0x00000000L, 0xffffffffL), beatBytes=64)
    //val accept = LazyModule(new AXI4FuzzSlave())

    //axi4 interconnect
    val xbar = AXI4Xbar()//xbar is the node of AXI4Xbar

    //connection
    accept.node := xbar

//    drivers.zipWithIndex.foreach {case(d,i) => (xbar
//      := TLToAXI4()
//      := TLRAMModel(s"Master $i")
//      := d.node)}
    drivers.zipWithIndex.foreach { case (d, i) => (xbar
      := d.node)
    }

    lazy val module = new LazyModuleImp (this) {

    }
    override lazy val desiredName = "xbarTestHarness"

}

class myAXI4Module() extends Module {
	val myAXI4BundleParameters = new AXI4BundleParameters(addrBits=32, dataBits=512, idBits=7)
	val io = IO(new Bundle {
		//val in = Flipped(new AXI4Bundle(myAXI4BundleParameters))
		val out = new AXI4Bundle(myAXI4BundleParameters)
	})
	io.out <> DontCare
	dontTouch(io.out)
}

object AxiMain extends App {
 println("Generating Hardware")
//  val verilog = (new ChiselStage).emitVerilog(LazyModule(new AdderTestHarness()(Parameters.empty)).module, Array("--target-dir","generated"))
//  println (s"``` verilog \n$verilog```")
    //implicit val valName:ValName = new ValName("MyAxiCrossbar")
    implicit val p = Parameters.empty
    val verilog = (new ChiselStage).emitVerilog(LazyModule(new xbarTestHarness()).module,Array("--target-dir","generated"))
    //val verilog2 = (new ChiselStage).emitVerilog(LazyModule(new AXI4XbarFuzzTest("Xbar DUT21", 5000, 2,1)).module)
	//val verilog3 = (new ChiselStage).emitVerilog(new myAXI4Module(),Array("--target-dir","generated"))
}
